package com.ruoyi.common.utils.a2;

import com.ruoyi.common.utils.IdentitiesUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 航迹预测算法.
 *
 * @author :yanlixiong
 * @date :2025-02-24 18:12:10
 */
public class TrajectoryPredictorUtils {

    // 地球半径(km)
    private static final double EARTH_RADIUS = 6371.0;
    private static final Random random = new Random();

    // 主预测方法
    public static List<TrajectoryPoint> predictTrajectory(List<TrajectoryPoint> historicalData) {
        long timestampVariation = IdentitiesUtils.getTimestampVariation();
        List<TrajectoryPoint> predictedData = new ArrayList<>();

        // 获取历史数据的最后一个点作为起点
        TrajectoryPoint lastPoint = historicalData.get(historicalData.size() - 1);

        // 计算平均时间间隔
        long timeInterval = (historicalData.get(historicalData.size() - 1).timestamp - historicalData.get(0).timestamp) / (historicalData.size() - 1);

        for (int i = 0; i < historicalData.size(); i++) {
            // 在上一次预测点基础上进行随机偏移
            TrajectoryPoint previousPoint = i == 0 ? lastPoint : predictedData.get(i - 1);

            // 随机调整航向（±30度范围内）
            double wayVariation = (random.nextDouble() - 0.5) * 60.0;
            double newWay = (previousPoint.way + wayVariation) % 360.0;
            if (newWay < 0) newWay += 360.0;

            // 随机调整速度（±20%范围内）
            double speedVariation = (random.nextDouble() - 0.5) * 0.4;
            double newSpeed = Math.max(10.0, previousPoint.speed * (1 + speedVariation));

            // 计算时间戳
            long newTimestamp = previousPoint.timestamp + timeInterval + timestampVariation;

            // 计算新的经纬度
            double distance = newSpeed * (timeInterval / 3600000.0); // 转换为小时
            double[] newCoordinates = calculateNewPosition(
                    previousPoint.lat,
                    previousPoint.lon,
                    distance,
                    newWay
            );

            predictedData.add(new TrajectoryPoint(
                    newCoordinates[1],  // lon
                    newCoordinates[0],  // lat
                    newSpeed,
                    newWay,
                    newTimestamp
            ));
        }

        return predictedData;
    }

    // 计算新位置的经纬度
    private static double[] calculateNewPosition(double lat, double lon, double distance, double bearing) {
        double lat1 = Math.toRadians(lat);
        double lon1 = Math.toRadians(lon);
        double brng = Math.toRadians(bearing);
        double d = distance / EARTH_RADIUS;

        double lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) +
                Math.cos(lat1) * Math.sin(d) * Math.cos(brng));
        double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(d) * Math.cos(lat1),
                Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));

        return new double[]{Math.toDegrees(lat2), Math.toDegrees(lon2)};
    }

    public static void main(String[] args) {
        // 模拟从日本到台湾的10条历史航迹数据（大致从东京到台北）
        List<TrajectoryPoint> historicalData = new ArrayList<>();
        long baseTime = System.currentTimeMillis();

        // 东京(139.6917°E, 35.6895°N) 到 台北(121.5654°E, 25.0330°N)
        double lonStep = (121.5654 - 139.6917) / 9;
        double latStep = (25.0330 - 35.6895) / 9;

        for (int i = 0; i < 20; i++) {
            historicalData.add(new TrajectoryPoint(
                    139.6917 + lonStep * i,     // lon
                    35.6895 + latStep * i,      // lat
                    50.0 + random.nextDouble() * 10, // speed: 50-60 km/h
                    225.0 + random.nextDouble() * 10, // way: 西南方向
                    baseTime + i * 3600000      // 每小时递增
            ));
        }

        // 创建预测器并进行预测
        TrajectoryPredictorUtils predictor = new TrajectoryPredictorUtils();

        System.out.println("历史数据：");
        historicalData.forEach(System.out::println);

        System.out.println("\n预测数据1：");
        List<TrajectoryPoint> predictedData1 = predictor.predictTrajectory(historicalData);
        predictedData1.forEach(System.out::println);

        System.out.println("\n预测数据2：");
        List<TrajectoryPoint> predictedData2 = predictor.predictTrajectory(historicalData);
        predictedData2.forEach(System.out::println);
    }
}
